package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zzyl.base.ResponseResult;
import com.zzyl.client.Factory;
import com.zzyl.constant.AccraditationRecordConstant;
import com.zzyl.constant.RetreatConstant;
import com.zzyl.dto.CheckInDto;
import com.zzyl.dto.ElderDto;
import com.zzyl.dto.MemberElderDto;
import com.zzyl.entity.*;
import com.zzyl.mapper.*;
import com.zzyl.service.*;
import com.zzyl.utils.CodeUtil;
import com.zzyl.utils.ObjectUtil;
import com.zzyl.utils.UserThreadLocal;
import com.zzyl.vo.*;
import com.zzyl.vo.retreat.ElderVo;
import com.zzyl.vo.retreat.TasVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author sjqn
 * @date 2023/11/7
 */
@Service
@Slf4j
public class CheckInServiceImpl implements CheckInService {


    @Autowired
    private ElderService elderService;

    @Autowired
    private CheckInMapper checkInMapper;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    private static final String CHECK_IN_CODE_PREFIX = "RZ";

    @Autowired
    private AccraditationRecordService accraditationRecordService;

    @Autowired
    private ActFlowCommService actFlowCommService;

    /**
     * 入住申请
     *
     * @param checkInDto
     * @return
     */
    @Override
    public ResponseResult createCheckIn(CheckInDto checkInDto) {

        //1.检验老人是否是入住中
        ElderVo elderVo = elderService.selectByIdCardAndName(checkInDto.getElderDto().getIdCardNo(), checkInDto.getElderDto().getName());
        if (null != elderVo && elderVo.getStatus().equals(4)) {
            return ResponseResult.error(checkInDto.getElderDto().getName() + "已经发起了入住申请");
        }

        //2.保存老人数据
        ElderDto elderDto = BeanUtil.toBean(checkInDto.getElderDto(), ElderDto.class);

        //年龄、性别、头像
        elderDto.setImage(checkInDto.getUrl1());
        /* JSONObject jsonObject = BeanUtil.toBean(checkInDto.getOtherApplyInfo(), JSONObject.class);*/
        JSONObject jsonObject = JSON.parseObject(checkInDto.getOtherApplyInfo());
        elderDto.setSex(jsonObject.getInteger("sex").toString());
        elderDto.setAge(jsonObject.getInteger("age").toString());

        Elder elder = elderService.insert(elderDto);

        CheckIn checkIn = null;

        //获取当前登录人的信息
        String subject = UserThreadLocal.getSubject();
        User user = JSONUtil.toBean(subject, User.class);

        if(checkInDto.getId() != null){
            //查询入住信息
            checkIn = checkInMapper.selectByPrimaryKey(checkInDto.getId());

            //老人要修改
            checkIn.setElderDto(elderDto);
            checkIn.setElderId(elder.getId());
            checkIn.setTitle(elder.getName()+ "的入住申请");
            //状态要修改
            checkIn.setFlowStatus(CheckIn.FlowStatus.REVIEW.getCode());
            checkIn.setOtherApplyInfo(JSONUtil.toJsonStr(checkInDto));
            checkInMapper.updateByPrimaryKeySelective(checkIn);
        }else {
            //3.保存入住数据
            checkIn = new CheckIn();
            //编号
            String code = CodeUtil.generateCode(CHECK_IN_CODE_PREFIX, redisTemplate, 5);
            checkIn.setCheckInCode(code);
            //标题
            checkIn.setTitle(elder.getName() + "的入住申请");
            checkIn.setElderId(elder.getId());

            checkIn.setCounselor(user.getRealName());
            checkIn.setApplicat(user.getRealName());
            checkIn.setApplicatId(user.getId());
            checkIn.setDeptNo(user.getDeptNo());
            //状态
            checkIn.setFlowStatus(CheckIn.FlowStatus.REVIEW.getCode());
            checkIn.setStatus(CheckIn.Status.APPLICATION.getCode());
            //其他信息
            checkInDto.setElderDto(elderDto);
            checkIn.setOtherApplyInfo(JSONUtil.toJsonStr(checkInDto));

            checkInMapper.insert(checkIn);
        }





        //5.启动流程实例
        if(ObjectUtil.isNotEmpty(checkInDto.getTaskId())){
            //完成任务
            actFlowCommService.completeProcess(checkIn.getTitle(),checkInDto.getTaskId(),user.getId().toString(),1,null);
        }else {
            //4.准备流程变量的参数 map
            Map<String, Object> variables = setVariables(checkIn);
            // 业务相关，登录用户相关、processDefinitionKey(checkIn-new)、首节点是否自动执行
            actFlowCommService.start(checkIn.getId(), user, "checkIn-new", variables, true);
        }

        //获取下一个审核人
        Long nextAssignee = actFlowCommService.getNextAssignee("checkIn-new", "checkIn-new:" + checkIn.getId());

        //6.保存操作记录
        RecordVo recordVo = getRecordVo(
                checkIn, user, AccraditationRecordConstant.AUDIT_STATUS_PASS,
                "同意", "发起申请-申请入住", "护理组组长处理-入住评估",
                nextAssignee
                , AccraditationRecordConstant.RECORD_HANDLE_TYPE_PROCESSED
        );

        accraditationRecordService.insert(recordVo);

        return ResponseResult.success();
    }

    /**
     * 封装审核记录参数
     *
     * @param checkIn      入住对象
     * @param user         当前登录用户
     * @param status       审核状态
     * @param option       操作意见
     * @param step         当前步骤
     * @param nextSetp     下一步操作人
     * @param nextAssignee 下一个审核人
     * @param handleType   处理类型（0:已审批，1：已处理）
     * @return
     */
    private RecordVo getRecordVo(CheckIn checkIn, User user, Integer status, String option, String step, String nextSetp, Long nextAssignee, Integer handleType) {

        RecordVo recordVo = new RecordVo();
        recordVo.setId(checkIn.getId());
        recordVo.setType(AccraditationRecordConstant.RECORD_TYPE_CHECK_IN);
        recordVo.setFlowStatus(checkIn.getFlowStatus());
        recordVo.setHandleType(handleType);
        recordVo.setStatus(status);
        recordVo.setOption(option);
        recordVo.setNextStep(nextSetp);
        recordVo.setNextAssignee(nextAssignee);
        recordVo.setUserId(user.getId());
        recordVo.setStep(step);
        recordVo.setRealName(user.getRealName());

        return recordVo;
    }

    @Autowired
    private DeptMapper deptMapper;

    @Autowired
    private UserMapper userMapper;

    /**
     * 封装变量数据
     *
     * @param checkIn
     * @return
     */
    private Map<String, Object> setVariables(CheckIn checkIn) {
        Map<String, Object> variables = new HashMap<>();

        //申请入住 - 养老顾问
        variables.put("assignee0", checkIn.getApplicatId());
        variables.put("processTitle",checkIn.getTitle());
        variables.put("assignee0Name", checkIn.getApplicat());
        variables.put("applicationTime",checkIn.getCreateTime());

        //入住评估 - 护理主管
        String nursingDeptCode = RetreatConstant.NURSING_DEPT_CODE;
        Dept dept = deptMapper.selectByDeptNo(nursingDeptCode);
        variables.put("assignee1", dept.getLeaderId());

        // 审核 副院长
        List<Long> idList = userMapper.selectByDeptNo(RetreatConstant.DEAN_OFFICE_DEPT_CODE);
        variables.put("assignee2", idList.get(0));

        // 入住选配 养老顾问
        variables.put("assignee3", checkIn.getApplicatId());

        //签约  法务
        List<Long> useridList = userMapper.selectByDeptNo(RetreatConstant.LEGAL_DEPT_CODE);
        variables.put("assignee4", useridList.get(useridList.size() - 1));

        //业务类型
        variables.put("processType", 3);

        //业务状态
        variables.put("processStatus", 1);

        //流程类型 code
        variables.put("processCode", checkIn.getCheckInCode());

        return variables;
    }

    @Autowired
    private AccraditationRecordMapper accraditationRecordMapper;

    @Autowired
    private CheckInConfigService checkInConfigService;

    @Autowired
    private NursingLevelMapper nursingLevelMapper;

    @Autowired
    private ContractMapper contractMapper;


    /**
     * 查询入住表单
     * @param assigneeId
     * @param code
     * @param flowStatus  流程状态，前端传递的状态
     * @param taskId  任务id,当前登录人的任务（）
     * @return
     */
    @Override
    public ResponseResult<TasVo> getCheckIn(String assigneeId, String code, Integer flowStatus, String taskId) {

        CheckIn checkIn = checkInMapper.selectByCheckInCode(code);
        CheckInVo checkInVo = BeanUtil.toBean(checkIn, CheckInVo.class);

        //先获取到所有的入住填写的表单数据
        String otherApplyInfo = checkIn.getOtherApplyInfo();
        JSONObject jsonObject = JSON.parseObject(otherApplyInfo, JSONObject.class);//相当于一个map
        if(ObjectUtil.isNotEmpty(jsonObject)){

            //获取老人数据
            ElderDto elderDto = JSON.parseObject(jsonObject.getString("elderDto"), ElderDto.class);
            checkInVo.setElderDto(elderDto);

            //获取家属信息  列表
            List<MemberElderDto> memberElderDtos = JSON.parseArray(jsonObject.getString("memberElderDtos"), MemberElderDto.class);
            checkInVo.setMemberElderDtos(memberElderDtos);

            //老人的其他信息
            checkInVo.setOtherApplyInfo(jsonObject.getString("otherApplyInfo"));

            //老人的头像身份照片信息
            checkInVo.setUrl1(jsonObject.getString("url1"));
            checkInVo.setUrl2(jsonObject.getString("url2"));
            checkInVo.setUrl3(jsonObject.getString("url3"));

        }

        //设置评估数据
        JSONObject reviewInfoJsonObj = JSON.parseObject(checkIn.getReviewInfo(),JSONObject.class);
        if(ObjectUtil.isNotEmpty(reviewInfoJsonObj)){
            checkInVo.setReviewInfo(reviewInfoJsonObj.getString("reviewInfo"));
            checkInVo.setReviewInfo1(reviewInfoJsonObj.getString("reviewInfo1"));
            checkInVo.setReviewInfo2(reviewInfoJsonObj.getString("reviewInfo2"));
        }

        //查询入住配置数据
        CheckInConfig checkInConfig = checkInConfigService.findCurrentConfigByElderId(checkIn.getElderId());
        CheckInConfigVo checkInConfigVo = BeanUtil.toBean(checkInConfig, CheckInConfigVo.class);
        if(ObjectUtil.isNotEmpty(checkInConfig)){
            //护理等级的对象
            NursingLevel nursingLevel = nursingLevelMapper.getById(checkInConfig.getNursingLevelId());
            NursingLevelVo nursingLevelVo = BeanUtil.toBean(nursingLevel, NursingLevelVo.class);
            checkInVo.setNursingLevelVo(nursingLevelVo);

            //楼层房间床位
            String[] arr = checkInConfig.getRemark().split(":");
            checkInConfigVo.setFloorId(Long.valueOf(arr[0]));
            checkInConfigVo.setRoomId(Long.valueOf(arr[1]));
            checkInConfigVo.setBedId(Long.valueOf(arr[2]));
            checkInConfigVo.setFloorName(arr[3]);
            checkInConfigVo.setCode(arr[4]);
            checkInVo.setCheckInConfigVo(checkInConfigVo);
        }

        //合同数据
        Contract contract = contractMapper.selectByElderId(checkIn.getElderId());
        if(ObjectUtil.isNotEmpty(contract)){
            ContractVo contractVo = BeanUtil.toBean(contract, ContractVo.class);
            checkInVo.setContractVo(contractVo);
        }



        TasVo tasVo = new TasVo();
        tasVo.setCheckIn(checkInVo);
        tasVo.setType(AccraditationRecordConstant.RECORD_TYPE_CHECK_IN);
        //获取操作记录
        List<AccraditationRecord> recordList = accraditationRecordMapper.getAccraditationRecordByBuisId(checkIn.getId(), AccraditationRecordConstant.RECORD_TYPE_CHECK_IN);
        tasVo.setAccraditationRecords(recordList);

        //isShow  1:展示数据和操作记录    0 ： 只展示操作记录
        //taskId  是当前登录人的一个任务，这个任务可能是没执行过的，也可能是执行过的
        int isShow = 1;

        //判断当前登录人是否是执行人，假如是执行人，就返回1，不是执行人返回0
        //flowStatus 0 1 2 3 4    待执行的状态
        //创建了申请单（养老顾问）  流程状态为多少？
        //formKey == 1  && 数据库库中的流程状态是1   返回的1，其他返回0

        //前端传递flowStatus，如果是默认的传的是-1
        if(flowStatus < 0){
            flowStatus = checkIn.getFlowStatus();
        }

        if(ObjectUtil.isNotEmpty(taskId) && checkIn.getStatus().equals(CheckIn.Status.APPLICATION.getCode())){
            isShow = actFlowCommService.isCurrentUserAndStep(taskId,flowStatus,checkIn.getFlowStatus());
        }


        boolean isRevacation = false;
        if(isShow == 2 && checkIn.getStatus().equals(CheckIn.Status.APPLICATION.getCode())){
            isRevacation = true;
        }

        //显示撤回按钮
        tasVo.setIsRevocation(isRevacation);

        if(isShow == 2){
            isShow = 1;
        }



        tasVo.setIsShow(isShow);

        return ResponseResult.success(tasVo);
    }

    /**
     * 入住评估
     * @param checkInDto
     * @return
     */
    @Override
    public ResponseResult review(CheckInDto checkInDto) {

        //查询入住数据
        CheckIn checkIn = checkInMapper.selectByPrimaryKey(checkInDto.getId());
        //修改流程状态
        checkIn.setFlowStatus(CheckIn.FlowStatus.APPROVAL.getCode());
        //保存健康评估数据
        checkIn.setReviewInfo(JSON.toJSONString(checkInDto));
        //修改数据
        checkInMapper.updateByPrimaryKeySelective(checkIn);

        //获取当前登录信息
        String subject = UserThreadLocal.getSubject();
        User user = JSON.parseObject(subject, User.class);

        //完成任务
        actFlowCommService.completeProcess("",checkInDto.getTaskId(),user.getId().toString(),1,null);

        Long nextAssignee = actFlowCommService.getNextAssignee("checkIn-new", "checkIn-new:" + checkIn.getId());

        //保存操作记录
        RecordVo recordVo = getRecordVo(
                checkIn, user, AccraditationRecordConstant.AUDIT_STATUS_PASS,
                "同意",  "护理部组长处理-入住评估",
                "院长处理-入住审批",
                nextAssignee
                , AccraditationRecordConstant.RECORD_HANDLE_TYPE_PROCESSED
        );
        accraditationRecordService.insert(recordVo);


        return ResponseResult.success();
    }

    /**
     * 同意
     * @param id
     * @param taskId
     * @param message
     * @return
     */
    @Override
    public ResponseResult submitCheckIn(Long id, String taskId, String message) {

        //查询入住数据
        CheckIn checkIn = checkInMapper.selectByPrimaryKey(id);
        checkIn.setFlowStatus(CheckIn.FlowStatus.CONFIG.getCode());
        checkInMapper.updateByPrimaryKeySelective(checkIn);

        //获取当前登录信息
        String subject = UserThreadLocal.getSubject();
        User user = JSON.parseObject(subject, User.class);

        //完成任务
        actFlowCommService.completeProcess("",taskId,user.getId().toString(),1,null);

        Long nextAssignee = actFlowCommService.getNextAssignee("checkIn-new", "checkIn-new:" + checkIn.getId());

        //保存操作记录
        RecordVo recordVo = getRecordVo(
                checkIn, user, AccraditationRecordConstant.AUDIT_STATUS_PASS,
                message,  "院长处理-入住审批",
                "养老顾问处理-入住配置",
                nextAssignee
                , AccraditationRecordConstant.RECORD_HANDLE_TYPE_AUDIT
        );
        accraditationRecordService.insert(recordVo);



        return ResponseResult.success();
    }

    /**
     * 审核拒绝
     * @param id
     * @param taskId
     * @param message
     * @return
     */
    @Override
    public ResponseResult auditReject(Long id, String taskId, String message) {
        //查询入住数据
        CheckIn checkIn = checkInMapper.selectByPrimaryKey(id);
        checkIn.setStatus(CheckIn.Status.CLOSED.getCode());
        checkInMapper.updateByPrimaryKeySelective(checkIn);
        close(checkIn.getElderId());

        //获取当前登录信息
        String subject = UserThreadLocal.getSubject();
        User user = JSON.parseObject(subject, User.class);
        //保存操作记录
        RecordVo recordVo = getRecordVo(
                checkIn, user, AccraditationRecordConstant.AUDIT_STATUS_REJECT,
                message,   "院长处理-入住审批",
                null,
                null
                , AccraditationRecordConstant.RECORD_HANDLE_TYPE_AUDIT
        );
        accraditationRecordService.insert(recordVo);

        //完成任务
        actFlowCommService.completeProcess("",taskId,user.getId().toString(),2,CheckIn.Status.CLOSED.getCode());

        return ResponseResult.success();

    }

    /**
     * 驳回
     * @param id
     * @param taskId
     * @param message
     * @return
     */
    @Override
    public ResponseResult disapprove(Long id, String taskId, String message) {

        CheckIn checkIn = checkInMapper.selectByPrimaryKey(id);
        //设置流程状态
        checkIn.setFlowStatus(CheckIn.FlowStatus.APPLY.getCode());

        checkInMapper.updateByPrimaryKeySelective(checkIn);

        //清理老人数据
        close(checkIn.getElderId());

        //获取当前登录信息
        String subject = UserThreadLocal.getSubject();
        User user = JSON.parseObject(subject, User.class);

        //完成任务
        actFlowCommService.completeProcess("",taskId,user.getId().toString(),3,null);
        //操作记录
        //保存审核记录
        RecordVo recoreVo = getRecordVo(checkIn,
                user,
                AccraditationRecordConstant.AUDIT_STATUS_DISAPPROVE,
                message, "驳回申请-入住审批", "养老顾问处理-入住申请",
                checkIn.getApplicatId(),
                AccraditationRecordConstant.RECORD_HANDLE_TYPE_PROCESSED);
        accraditationRecordService.insert(recoreVo);

        return ResponseResult.success();
    }

    private void close(Long id){
        elderService.deleteByPrimaryKey(id);
    }

    /**
     * 撤回
     * @param id
     * @param flowStatus
     * @param taskId
     * @return
     */
    @Override
    public ResponseResult revocation(Long id, String flowStatus, String taskId) {

        //修改状态
        CheckIn checkIn = checkInMapper.selectByPrimaryKey(id);
        //设置流程状态
        checkIn.setFlowStatus(CheckIn.FlowStatus.APPROVAL.getCode());
        checkInMapper.updateByPrimaryKeySelective(checkIn);

        //获取当前登录信息
        String subject = UserThreadLocal.getSubject();
        User user = JSON.parseObject(subject, User.class);


        //完成任务
        actFlowCommService.withdrawTask(taskId,false);

        //操作记录
        //第一个参数是条件，第二个参数为匹配到的值
        String name = EnumUtil.getBy(CheckIn.FlowStatus::getCode, checkIn.getFlowStatus()).getName();

        RecordVo recoreVo = getRecordVo(checkIn,
                user,
                AccraditationRecordConstant.AUDIT_STATUS_WITHDRAWS,
                "撤回",
                "撤回申请-" + name, "",
                user.getId(),
                AccraditationRecordConstant.RECORD_HANDLE_TYPE_PROCESSED);
        accraditationRecordService.insert(recoreVo);

        return ResponseResult.success();
    }

    /**
     * 撤销
     * @param id
     * @param taskId
     * @return
     */
    @Override
    public ResponseResult cancel(Long id, String taskId) {

        //修改状态
        CheckIn checkIn = checkInMapper.selectByPrimaryKey(id);
        //设置流程状态
        checkIn.setStatus(CheckIn.Status.CLOSED.getCode());
        checkInMapper.updateByPrimaryKeySelective(checkIn);
        //删除老人数据
        close(checkIn.getElderId());

        //获取当前登录信息
        String subject = UserThreadLocal.getSubject();
        User user = JSON.parseObject(subject, User.class);


        //撤销任务
        actFlowCommService.cancelProcess(taskId);


        //保存操作记录
        RecordVo recoreVo = getRecordVo(checkIn,
                user,
                AccraditationRecordConstant.AUDIT_STATUS_CANCEL,
                "撤销",
                "申请人-撤销", "",
                null,
                AccraditationRecordConstant.RECORD_HANDLE_TYPE_PROCESSED);
        accraditationRecordService.insert(recoreVo);

        return ResponseResult.success();
    }
}
